Emacs as a programming IDE

Marie-Hélène Burle

November 14, 2023


Why I still use (and love) Emacs

Yes, there are much simpler text editors, but they pale in comparison (apart from Vim)

https://cube-drone.com

And yes, there are now excellent IDEs for Python, Julia, and R without Emacs learning curve

So here are a few of my reasons:

  • Fully customizable
  • Key-bindings for everything
  • Undoing/redoing with undo-tree
  • Opening files
  • Bookmarking
  • Searching and navigation within files with helm
  • Search and replace with regexp
  • Creation of code snippets with yasnippet
  • Can be used for Emails, Slack, Telegram with mu4e, emacs-slack, telega

Example: undo/redo

Linear systems: classic undo/redo


flowchart TD
   1((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Have some file

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Make some edits

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Make more edits

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Make more edits

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current---4((" "))
   classDef current stroke: #f96, stroke-width: 2px

Can undo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" ")):::current---3((" "))---4((" "))
   classDef current stroke: #f96, stroke-width: 2px

Undo some more

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current---4((" "))
   classDef current stroke: #f96, stroke-width: 2px

Can redo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" "))-.-4((" ")):::lost
   3((" "))---5((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4

Make new edits

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current-.-4((" ")):::lost
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4

Can still undo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" ")):::current---3((" "))-.-4((" ")):::lost
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4

Can still undo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current-.-4((" ")):::lost
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4

And can redo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" "))-.-4((" ")):::lost
   3((" "))---5((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4

But some edits are forever lost

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1)):::current
   classDef current stroke: #f96, stroke-width: 2px

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2)):::current
   classDef current stroke: #f96, stroke-width: 2px

Make some edits

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3)):::current
   classDef current stroke: #f96, stroke-width: 2px

Make more edits

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4)):::current
   classDef current stroke: #f96, stroke-width: 2px

Make more edits

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3)):::current
   classDef current stroke: #f96, stroke-width: 2px

The first undo adds a new point to the chain of edits

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3))---6((2)):::current
   classDef current stroke: #f96, stroke-width: 2px

More undoing keeps adding points to the chain

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3))---6((2))---7((3)):::current
   classDef current stroke: #f96, stroke-width: 2px

There is no redo: you stop undoing, then start again to undo the undo

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3))---6((2))---7((3))---8((5)):::current
   classDef current stroke: #f96, stroke-width: 2px

You can make new edits

Nothing ever gets lost, but you might get headaches

Example: let’s go back to the starting point

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3))---6((2))---7((3))---8((5))---9((3))---10((2))---11((3))---12((4))---13((3))---14((2))---15((1)):::current
   classDef current stroke: #f96, stroke-width: 2px

Non linear system: undo-tree


flowchart TD
   1((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Make some edits

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Make some edits

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Make some edits

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" ")):::current---4((" "))
   classDef current stroke: #f96, stroke-width: 2px

Undo

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" ")):::current---3((" "))---4((" "))
   classDef current stroke: #f96, stroke-width: 2px

Undo

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" ")):::current---4((" "))
   classDef current stroke: #f96, stroke-width: 2px

Redo

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" "))
   3((" "))---5((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Make new edits

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" "))
   3((" ")):::current---5((" "))
   classDef current stroke: #f96, stroke-width: 2px

Undo

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" ")):::current
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px

Switch branch and redo the old version

Non linear system: undo-tree


flowchart TD
   1((" ")):::current---2((" "))---3((" "))---4((" "))
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px

Nothing gets lost and it is more sane to navigate the history

Emacs with Python

Emacs comes with a Python mode that provides syntax highlighting. For a full IDE experience, there are multiple options, the most popular of which being the elpy package

Code from matplotlib

Emacs with R

R is—as Emacs—GNU software and has been integrated with Emacs via the ESS (Emacs Speaks Statistics) package for a very long time

Emacs with Julia

The julia-mode package provides syntax highlighting and the julia-repl package implements a fully functional Julia REPL, optionally with the emacs-libvterm package

Code from Beautiful Makie

ESS also provides an IDE for Julia, but it does not allow for the funky Julia-specific REPL

Another sophisticated option is to use julia-mode with the julia-snail package

Time for a demo